using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using System.Reflection;
using RikMigrations.Providers;
using System.IO;

namespace RikMigrations.Tests
{
	public class MigrationManagerTests
	{
		protected DbProvider db;
		public MigrationManagerTests(DbProvider db)
		{
			this.db = db;
		}

		[SetUp]
		public virtual void Setup()
		{
			db.CreateTransaction();
		}

		[TearDown]
		public virtual void TearDown()
		{
			db.RollbackTransaction();
		}

		[Test]
		public void FindAllMigrations()
		{
			Dictionary<string, List<MigrationAttribute>> migrations = MigrationManager.FindAllMigrations(Assembly.GetExecutingAssembly());
			Assert.AreEqual(3, migrations.Keys.Count);
			Assert.AreEqual(4, migrations[MigrationManager.DefaultModuleName].Count);
			Assert.AreEqual(2, migrations["Module1"].Count);
			Assert.AreEqual(3, migrations["Module2"].Count);
		}

		#region UpgradeMax
		[Test]
		public void UpgradeMax()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.UpgradeMax(Assembly.GetExecutingAssembly(), db, null);
			Assert.AreEqual(4, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(2, db.GetModuleVersion("Module1"));
			Assert.AreEqual(3, db.GetModuleVersion("Module2"));
		}

		[Test]
		public void UpgradeMaxDefault()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.UpgradeMax(Assembly.GetExecutingAssembly(), db, MigrationManager.DefaultModuleName);
			Assert.AreEqual(4, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
		}

		[Test]
		public void UpgradeMaxModule1()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.UpgradeMax(Assembly.GetExecutingAssembly(), db, "Module1");
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(2, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
		}

		[Test]
		public void UpgradeMaxModule2()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.UpgradeMax(Assembly.GetExecutingAssembly(), db, "Module2");
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(3, db.GetModuleVersion("Module2"));
		}
		#endregion

		#region MigrateUp
		[Test]
		public void MigrateUpTo()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.MigrateTo(Assembly.GetExecutingAssembly(), null, 1, db);
			Assert.AreEqual(1, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
		}

		[Test]
		public void MigrateModule1UpTo()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.MigrateTo(Assembly.GetExecutingAssembly(), "Module1", 1, db);
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(1, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
		}

		[Test]
		public void MigrateModule2UpTo()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.MigrateTo(Assembly.GetExecutingAssembly(), "Module2", 1, db);
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(1, db.GetModuleVersion("Module2"));
		}

		[Test]
		public void MigrateModule2UpTo2()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.MigrateTo(Assembly.GetExecutingAssembly(), "Module2", 2, db);
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(2, db.GetModuleVersion("Module2"));
		}
		#endregion

		#region MigrateDown
		[Test]
		public void MigrateDownTo()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.UpgradeMax(Assembly.GetExecutingAssembly(), db);
			Assert.AreEqual(4, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(2, db.GetModuleVersion("Module1"));
			Assert.AreEqual(3, db.GetModuleVersion("Module2"));
			MigrationManager.MigrateTo(Assembly.GetExecutingAssembly(), null, 1, db);
			Assert.AreEqual(1, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(2, db.GetModuleVersion("Module1"));
			Assert.AreEqual(3, db.GetModuleVersion("Module2"));
		}

		[Test]
		public void MigrateModule1DownTo()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.UpgradeMax(Assembly.GetExecutingAssembly(), db);
			Assert.AreEqual(4, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(2, db.GetModuleVersion("Module1"));
			Assert.AreEqual(3, db.GetModuleVersion("Module2"));
			MigrationManager.MigrateTo(Assembly.GetExecutingAssembly(), "Module1", 1, db);
			Assert.AreEqual(4, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(1, db.GetModuleVersion("Module1"));
			Assert.AreEqual(3, db.GetModuleVersion("Module2"));
		}

		[Test]
		public void MigrateModule2DownTo()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.UpgradeMax(Assembly.GetExecutingAssembly(), db);
			Assert.AreEqual(4, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(2, db.GetModuleVersion("Module1"));
			Assert.AreEqual(3, db.GetModuleVersion("Module2"));
			MigrationManager.MigrateTo(Assembly.GetExecutingAssembly(), "Module2", 1, db);
			Assert.AreEqual(4, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(2, db.GetModuleVersion("Module1"));
			Assert.AreEqual(1, db.GetModuleVersion("Module2"));
		}

		[Test]
		public void MigrateModule2DownTo2()
		{
			Assert.AreEqual(0, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(0, db.GetModuleVersion("Module1"));
			Assert.AreEqual(0, db.GetModuleVersion("Module2"));
			MigrationManager.UpgradeMax(Assembly.GetExecutingAssembly(), db);
			Assert.AreEqual(4, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(2, db.GetModuleVersion("Module1"));
			Assert.AreEqual(3, db.GetModuleVersion("Module2"));
			MigrationManager.MigrateTo(Assembly.GetExecutingAssembly(), "Module2", 2, db);
			Assert.AreEqual(4, db.GetModuleVersion(MigrationManager.DefaultModuleName));
			Assert.AreEqual(2, db.GetModuleVersion("Module1"));
			Assert.AreEqual(2, db.GetModuleVersion("Module2"));
		}
		#endregion
	}

	[TestFixture]
	public class MssqlMigrationManagerTests : MigrationManagerTests
	{
		public MssqlMigrationManagerTests() : base(new MssqlProvider())
		{
		}

		[SetUp]
		public override void Setup()
		{
			db.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Test"].ConnectionString;
			base.Setup();
		}
	}

#if SQLITE
	[TestFixture]
	public class SqliteMigrationManagerTests : MigrationManagerTests
	{
		string dbPath;

		public SqliteMigrationManagerTests()
			: base(new SqliteProvider())
		{
		}

		[SetUp]
		public override void Setup()
		{
			dbPath = Path.GetTempFileName();
			db.ConnectionString = string.Format("Data Source={0}", dbPath);

			base.Setup();
		}

		[TearDown]
		public override void TearDown()
		{
			base.TearDown();
			File.Delete(dbPath);
		}
	}
#endif
}